package org.movee.net.cfg.parser.parser.cisco;

import org.movee.net.cfg.parser.domain.model.AddressFamilyType;
import org.movee.net.cfg.parser.domain.model.ConfigModel;
import org.movee.net.cfg.parser.utils.OrikaSupplier;
import ma.glasnost.orika.MapperFacade;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 *
 *
 * @author 
 */
public class CiscoConfigModelConverter implements Converter<CiscoConfigModel, ConfigModel> {

    private final MapperFacade orika = OrikaSupplier.ORIKA;

    @Nullable
    @Override
    public ConfigModel convert(@NonNull CiscoConfigModel source) {

        // netware
        ConfigModel.Netware netware = createNetware(source.getNetware());

        // ip和接口
        Map<String, ConfigModel.IpUnit> ipUnits = new TreeMap<>();
        Map<String, ConfigModel.InterfaceUnit> intfUnits = new TreeMap<>();
        for (CiscoConfigModel.Interface intf : source.getInterfaces().values()) {

            ConfigModel.Interface dstIntf = createIntf(intf);

            Set<String> ipv4s = new TreeSet<>();
            for (CiscoConfigModel.InterfaceIp ip : intf.getIps()) {
                ConfigModel.Ip dstIp = createIp(ip);
                ConfigModel.IpUnit ipUnit = createIpUnit(dstIp, dstIntf.getName());
                // 添加到接口和ip unit中
                ipv4s.add(dstIp.getIpAddress());
                ipUnits.put(dstIp.getIpAddress(), ipUnit);
            }

            Set<String> ipv6s = new TreeSet<>();
            for (CiscoConfigModel.InterfaceIp6 ip6 : intf.getIp6s()) {
                ConfigModel.Ip dstIp = createIp6(ip6);
                ConfigModel.IpUnit ipUnit = createIpUnit(dstIp, dstIntf.getName());
                // 添加到接口和ip unit中
                ipv6s.add(dstIp.getIpAddress());
                ipUnits.put(dstIp.getIpAddress(), ipUnit);
            }

            ConfigModel.InterfaceUnit intfUnit = createIntfUnit(dstIntf, "", new TreeSet<>(), ipv4s, ipv6s);
            intfUnits.put(dstIntf.getName(), intfUnit);
        }

        ConfigModel.Bgp bgp = createBgp(source.getBgp());

        return new ConfigModel()
                .setMgmtIp(source.getMgmtIp())
                .setTimestamp(source.getTimestamp())
                .setNetware(netware)
                .setInterfaces(intfUnits)
                .setIps(ipUnits)
                .setBgp(bgp);
    }

    private ConfigModel.Netware createNetware(CiscoConfigModel.Netware netware) {
        return orika.map(netware, ConfigModel.Netware.class);
    }

    private ConfigModel.Interface createIntf(CiscoConfigModel.Interface intf) {
        return orika.map(intf, ConfigModel.Interface.class);
    }

    private ConfigModel.InterfaceUnit createIntfUnit(ConfigModel.Interface intf,
                                                     String pIntf,
                                                     Set<String> cIntfs,
                                                     Set<String> ipv4s,
                                                     Set<String> ipv6s) {

        return new ConfigModel.InterfaceUnit(pIntf, intf, cIntfs, ipv4s, ipv6s);

    }

    private ConfigModel.Ip createIp(CiscoConfigModel.InterfaceIp ip) {
        ConfigModel.Ip dstIp = orika.map(ip, ConfigModel.Ip.class);
        dstIp.setFamily(AddressFamilyType.IPV4.name());
        return dstIp;
    }

    private ConfigModel.Ip createIp6(CiscoConfigModel.InterfaceIp6 ip) {
        ConfigModel.Ip dstIp = orika.map(ip, ConfigModel.Ip.class);
        dstIp.setFamily(AddressFamilyType.IPV6.name());
        return dstIp;
    }

    private ConfigModel.IpUnit createIpUnit(ConfigModel.Ip ip, String intfName) {
        return new ConfigModel.IpUnit()
                .setIp(ip)
                .setIntf(intfName);
    }

    private ConfigModel.Bgp createBgp(CiscoConfigModel.Bgp bgp) {
        if (bgp == null) {
            return null;
        }

        ConfigModel.Bgp dstBgp = orika.map(bgp, ConfigModel.Bgp.class);

        dstBgp.getPeers().clear();
        for (CiscoConfigModel.BgpPeer peer : bgp.getPeers().values()) {
            ConfigModel.BgpPeer dstPeer = orika.map(peer, ConfigModel.BgpPeer.class);
            dstBgp.getPeers().put(dstPeer.getPeerIp(), dstPeer);
        }
        return dstBgp;
    }

}
